﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for Data
/// </summary>
public class Data
{
    public static DataBusLineDataContext dataConect = new DataBusLineDataContext();
    public static List<Station> stations;
    public static List<BusRoute> busRoutes;
    public static List<StationToStation> stationToStation;
    public static List<Vertex> myStations;
    public static List<District> districts;
	public Data()
	{
		//
		// TODO: Add constructor logic here
		//
	}
    public static void loadData(double walk, double changeRoute1)
    {
        loadData(walk, changeRoute1, 0, 0, 0, 0);
    }
    public static void loadData(double walk, double changeRoute1, double longitude1, double latitude1, double longitude2, double latitude2)
    {
        bool isAdditionalPoints = longitude1 == 0 ? false : true;
        double changeRoute = Algorithm.toUnrealDistance(changeRoute1);
        stations = dataConect.Stations.ToList();
        stationToStation = dataConect.StationToStations.ToList();
        busRoutes = dataConect.BusRoutes.OrderBy(p => p.BusRouteNumber.ToString()).ToList();
        myStations = new List<Vertex>();
        if (isAdditionalPoints)
        {
            Station s1 = new Station();
            s1.Longitude = longitude1;
            s1.Latitude = latitude1;
            s1.AddressNumber = "Bắt đầu";
            s1.IDStation = 111111;
            stations.Add(s1);

            Station s2 = new Station();
            s2.Longitude = longitude2;
            s2.Latitude = latitude2;
            s2.AddressNumber = "Kết thúc";
            s2.IDStation = 222222;
            stations.Add(s2);

            
            //for (int i = 0; i < stations.Count; i++)
            foreach (Station t in stations)
            {
                StationToStation s2s = new StationToStation();
                s2s.IDStartStation = s1.IDStation;
                s2s.Nodes = s1.Latitude + "," + s1.Longitude + ";" + t.Latitude + "," + t.Longitude;
                s2s.Length = 1.5 * Algorithm.lenghtPointToPoint((double)s1.Longitude, (double)s1.Latitude, (double)t.Longitude, (double)t.Latitude);
                s2s.IDEndStation = t.IDStation;
                s2s.IDStationToStation = stations.IndexOf(t) + 10000;
                stationToStation.Add(s2s);

                StationToStation s2s_ = new StationToStation();
                s2s_.IDStartStation = t.IDStation;
                s2s_.Nodes = s2.Latitude + "," + s2.Longitude + ";" + t.Latitude + "," + t.Longitude;
                s2s_.Length = 1.5 * Algorithm.lenghtPointToPoint((double)s2.Longitude, (double)s2.Latitude, (double)t.Longitude, (double)t.Latitude);
                s2s_.IDEndStation = s2.IDStation;
                s2s_.IDStationToStation = stations.IndexOf(t) + 20000;
                stationToStation.Add(s2s_);
            }

        }
        //==========================================================================
        //1. Station for walker
        //2. Line for walker
        //3. Station for each bus point
        //4. Line between 2 station in a point
        //5. Line between 2 station at 2 point (in 1 route)
        //
        //==========================================================================
        //1. Station for walker
        foreach (Station st in stations)
        {
            Vertex temp = new Vertex();
            temp.id = st.IDStation;
            temp.flag = -1;
            myStations.Add(temp);
        }
        //==========================================================================
        //2. Create lines for walker station
        foreach (StationToStation s2s in stationToStation)
        {
            //Tạo đường đi bộ từ trạm đến trạm (khác tuyến)
            int fromIndex, toIndex;
            Vertex fromMyStation, toMyStation;
            try
            {
                fromMyStation = myStations.Single(p=>p.flag == -1 && p.id == s2s.IDStartStation);
                toMyStation = myStations.Single(p=>p.flag == -1 && p.id == s2s.IDEndStation);
                fromIndex = myStations.IndexOf(fromMyStation);
                toIndex = myStations.IndexOf(toMyStation);

                myStations[fromIndex].next.Add(toIndex);
                myStations[fromIndex].nextValue.Add(s2s.Length.Value*walk);
            }
            catch
            {

            }
        }
        //==========================================================================
        //3. Station with busRoute
        foreach (BusRoute br in busRoutes)
        {
            //Tạo đường từ trạm đến trạm (trên 1 tuyến)
            //Tạo đường chuyển trạm
            //Split string to array of station
            string[] str = br.Stations.Split(',');
            foreach (string a in str)
            {
                int x = 0;
                //if can change to int
                if (int.TryParse(a, out x))
                {
                    try
                    {
                        //if can find the station, add new bus line to it
                        Vertex temp = new Vertex();
                        temp.id = x;
                        temp.flag = br.IDBusRoute;
                        myStations.Add(temp);
                    }
                    catch { }
                }
            }
        }
        //===========================================================================
        //4. Line between 2 station in a point
        foreach (Station st in stations)
        {
            List<Vertex> myStationTemp = myStations.Where(p => p.id == st.IDStation).ToList();
            int[] stationIndex = new int[myStationTemp.Count];
            for (int i = 0; i < myStationTemp.Count; i++)
                stationIndex[i] = myStations.IndexOf(myStationTemp[i]);
            for (int i = 0; i < stationIndex.Length; i++)
                for (int j = 0; j < stationIndex.Length; j++)
                {
                    if (i == j) continue;
                    if (myStations[stationIndex[i]].flag != -1 && myStations[stationIndex[j]].flag != -1) continue;//Muốn chuyển tuyến phải xuống xe (flag=-1) trước rồi lên xe khác
                    myStations[stationIndex[i]].next.Add(stationIndex[j]);
                    if (myStations[stationIndex[j]].flag == -1)
                        myStations[stationIndex[i]].nextValue.Add(0);
                    else
                        myStations[stationIndex[i]].nextValue.Add(changeRoute);
                }
        }
        //=================================================================================
        //5. Line between 2 station at 2 point (in 1 route)
        foreach (BusRoute br in busRoutes)
        {
            List<int> stationId = new List<int>();
            //Split string to array of station
            string[] str = br.Stations.Split(',');
            foreach (string a in str)
            {
                int x = 0;
                //if can change to int
                if (int.TryParse(a, out x))
                        stationId.Add(x);
            }
            for (int i = 0; i<stationId.Count-1; i++)
            {
                try
                {
                    int fromStationIndex = myStations.IndexOf(myStations.Single(p => p.id == stationId[i] && p.flag == br.IDBusRoute));
                    int toStationIndex = myStations.IndexOf(myStations.Single(p => p.id == stationId[i+1] && p.flag == br.IDBusRoute));
                    myStations[fromStationIndex].next.Add(toStationIndex);
                    //Station a = stations.Single(p => p.IDStation == myStations[fromStationIndex].id);
                    //Station b = stations.Single(p => p.IDStation == myStations[toStationIndex].id);
                    StationToStation s2s = stationToStation.Single(p => p.IDStartStation == myStations[fromStationIndex].id && p.IDEndStation == myStations[toStationIndex].id);
                    
                    myStations[fromStationIndex].nextValue.Add(s2s.Length.Value);
                }
                catch { }
            }
        }
    }
    public static string upDateStation(int IDStation, string addressNumber, string street, string district, float longitude, float latitude)
    {
        try
        {
            Station a = dataConect.Stations.Single(p => p.IDStation == IDStation);
            a.AddressNumber = addressNumber;
            a.StreetName = street;
            a.DistrictName = district;
            a.Longitude = longitude;
            a.Latitude = latitude;
            dataConect.SubmitChanges();
            loadData(1,0);
            return "Cập nhật thành công";
        }
        catch
        {
            return "Cập nhật không thành công";
        }
    }
    public double lenghtVertexToVertex(Vertex a, Vertex b, double walk, double changeRoute)
    {
        try
        {
            StationToStation s2s = stationToStation.Where(p=>p.IDStartStation==a.id&&p.IDEndStation==b.id).ToArray()[0];
            if (a.id == -1 && b.id == -1)//Đi bộ từ trạm đến trạm
                return s2s.Length.Value*walk;
            if (a.id == b.id)
            {
                if (a.flag != b.flag)//Chuyển tuyến
                    return s2s.Length.Value + changeRoute;
                else
                    return 0;
            }
            return 0;
        }
        catch
        {
            return 1000000;
        }
    }
    public static string insertStation(string addressNumber, string street, string district, float longitude, float latitude)
    {
        try
        {
            Station station = new Station { AddressNumber = addressNumber,
                                            StreetName = street,
                                            DistrictName = district,
                                            Latitude = latitude,
                                            Longitude = longitude };
            dataConect.Stations.InsertOnSubmit(station);
            dataConect.SubmitChanges();
            loadData(1,0);
            Station _station = dataConect.Stations.SingleOrDefault(st=>st.IDStation==dataConect.Stations.Max(sta=>sta.IDStation));
            return _station.IDStation + "," + _station.Latitude + "," + _station.Longitude;
        }
        catch
        {
            return "";
        }
    }
    public static bool insertStationToStation(int id1, int id2)
    {
        try
        {
            dataConect.StationToStations.Single(p => p.IDStartStation == id1 && p.IDEndStation == id2);
            return false;
        }
        catch
        { }
        try
        {
            dataConect.Stations.Single(p => p.IDStation == id1);
        }
        catch
        {
            return false;
        }
        try
        {
            dataConect.Stations.Single(p => p.IDStation == id2);
        }
        catch
        {
            return false;
        }
        StationToStation a = new StationToStation();
        a.IDStartStation = id1;
        a.IDEndStation = id2;
        a.Length = 100000;
        dataConect.StationToStations.InsertOnSubmit(a);
        dataConect.SubmitChanges();
        loadData(1,0);
        return true;
    }
    public static bool insertBusRoute()
    {
        try
        {
            BusRoute a = new BusRoute();
            a.BusRouteName = "Từ - Đến";
            a.BusRouteNumber = "0";
            a.Stations = "";
            dataConect.BusRoutes.InsertOnSubmit(a);
            dataConect.SubmitChanges();
            loadData(1,0);
            return true;
        }
        catch
        {
            return false;
        }
    }
    public static bool updateBusRoute(int idBusRoute, string name, string stations, string number)
    {
        try
        {
            BusRoute a = dataConect.BusRoutes.Single(p => p.IDBusRoute == idBusRoute);
            a.BusRouteName = name;
            a.BusRouteNumber = number;
            a.Stations = stations;
            string[] temp = stations.Split(',');
            foreach (string s in temp)
            {
                try
                {
                    dataConect.Stations.Single(p => p.IDStation == int.Parse(s));
                }
                catch
                {
                    return false;
                }
            }
            
            dataConect.SubmitChanges();
            loadData(1,0);
            return true;
        }
        catch
        {
            return false;
        }

    }
    public static string getBusRouteToDraw(int id)
    {
        try
        {
            BusRoute a = busRoutes.Single(p => p.IDBusRoute == id);
            string[] temp = a.Stations.Split(',');
            List<Station> st = new List<Station>();
            foreach (string s in temp)
            {
                st.Add(dataConect.Stations.Single(p => p.IDStation == int.Parse(s)));
            }
            string result = "";
            for (int i = 0; i < st.Count-1; i++)
            {
                StationToStation s2s = stationToStation.Single(p => p.IDStartStation.Value == st[i].IDStation && p.IDEndStation.Value == st[i + 1].IDStation);
                if (i > 0)
                {
                    result += s2s.Nodes;
                    if (i < st.Count - 2)
                        result += ";";
                }
                else
                {
                    result += s2s.Nodes;
                    if (i < st.Count - 2)
                        result += ";";
                }
            }
            return result;
        }
        catch
        {
            return null;
        }
    }
    public static BusRoute getBusRoute(int id)
    {
        try
        {
            return busRoutes.Single(p => p.IDBusRoute == id);
        }
        catch
        {
            return null;
        }
    }
    public static BusRoute[] getBusRoutes()
    {
        return busRoutes.ToArray();
    }
    public static string updateStationToStation(int id1, int id2, string nodes)
    {
        try
        {
            StationToStation a = dataConect.StationToStations.Single(p => p.IDStartStation == id1 && p.IDEndStation == id2);
            a.Nodes = nodes;
            a.Length = calulateLengthofNodes(a.Nodes);
            if (a.Length==100000)
                return "Chi tiết không đúng định dạng, sửa không thành công";
            dataConect.SubmitChanges();
            loadData(1,0);
            return "Sửa thành công!";
        }
        catch
        {
            return "Không tìm thấy, sửa không thành công";
        }
        
    }
    public static string[] getWayStationToOtherStation(int id1)
    {
        try
        {
            List<StationToStation> a = dataConect.StationToStations.Where(p => p.IDStartStation == id1).ToList();
            if (a.Count == 0) return null;
            List<string> result = new List<string>();
            foreach (StationToStation t in a)
                result.Add(t.Nodes);
            return result.ToArray();
        }
        catch
        {
            return null;
        }

    }
    public static double calulateLengthofNodes(string nodes)
    {
        try
        {
            List<double> x, y;
            x = new List<double>();
            y = new List<double>();
            double result = 0;
            string[] temp = nodes.Split(';');
            for (int i = 0; i < temp.Length; i++)
            {
                string[] temp1 = temp[i].Split(',');
                x.Add(Double.Parse(temp1[0]));
                y.Add(Double.Parse(temp1[1]));
            }
            for (int i = 1; i < x.Count; i++)
                result += Math.Sqrt(
                                  (x[i] - x[i - 1]) * (x[i] - x[i - 1]) +
                                  (y[i] - y[i - 1]) * (y[i] - y[i - 1])
                                  );
            return result;
        }
        catch
        {
            return 100000;
        }
    }
    public static StationToStation[] getStationToStation(int idBegin)
    {
        return dataConect.StationToStations.Where(p => p.IDStartStation == idBegin).ToArray();
    }
    public static StationToStation getStationToStation(int idBegin, int idEnd)
    {
        List<StationToStation> a = dataConect.StationToStations.Where(p => p.IDStartStation == idBegin && p.IDEndStation==idEnd).ToList();
        if (a.Count == 0)
            return null;
        else
            return a[0];
    }
    
    public static string[] findPathBetweenTwoStation(int idStation1, int idStation2, double walk, double changeRoute)
    {
        //changeRoute = Algorithm.toUnrealDistance(changeRoute);
        loadData(walk, changeRoute);
        int begin = Data.myStations.IndexOf(Data.myStations.Single(p => p.id == idStation1 && p.flag == -1));
        int end = Data.myStations.IndexOf(Data.myStations.Single(p => p.id == idStation2 && p.flag == -1));
        int[] result = Algorithm.AStart(Data.myStations.ToArray(), begin, end, walk, changeRoute);
        List<string> b = new List<string>();
        b = Algorithm.changeStationToLine(result, myStations).ToList();
        return b.ToArray();
        //return findPathBetweenTwoStation((double)106.696429, (double)10.8032722, (double)106.716749, (double)10.8043893, (double)2, (double)0);
        //10.8043893,106.716749
    }
    public static string[] findPathBetweenTwoStation(double longitude1, double latitude1, double longitude2, double latitude2, double walk, double changeRoute)
    {
        //changeRoute = Algorithm.toUnrealDistance(changeRoute);
        //Dang sua o day v8
        loadData(walk, changeRoute, longitude1, latitude1, longitude2, latitude2);

        int idStart = -1;
        double crrLengthStart = 10000;
        int idEnd = -1;
        double crrLengthEnd = 10000;
        // Find station nearest start point & end point.
        /*for (int i = 0; i < myStations.Count; i++)
        {
            if (myStations[i].flag != -1) continue;
            Station t = stations.Single(p => p.IDStation==myStations[i].id);
            double length = Algorithm.lenghtPointToPoint(longitude1, latitude1, t.Longitude.Value, t.Latitude.Value);
            if (length < crrLengthStart)
            {
                crrLengthStart = length;
                idStart = i;
            }
            length = Algorithm.lenghtPointToPoint(longitude2, latitude2, t.Longitude.Value, t.Latitude.Value);
            if (length < crrLengthEnd)
            {
                crrLengthEnd = length;
                idEnd = i;
            }
        }*/
        for (int i = 0; i < myStations.Count; i++)
        {
            Station t = stations.Single(p => p.IDStation == myStations[i].id);
            if (t.IDStation == 111111)
                idStart = i;
            if (t.IDStation == 222222)
                idEnd = i;
        }
        int[] result = Algorithm.AStart(Data.myStations.ToArray(), idStart, idEnd, walk, changeRoute);
        List<string> b = new List<string>();
        //b[0] = "";
        b = Algorithm.changeStationToLine(result, myStations).ToList();
        //b.Add("Chỉ dẫn đường đi");
        return b.ToArray();
    }
}
public struct Position
{
    public double Longitude;
    public double Latitude;
}
public struct nextStaion
{
    public int IDNextStation;
    public double length;
}
public class MyStation
{
    public int IDStation { get; set; }
    public List<nextStaion> nextStation { get; set; }
    public List<int> IDBusRoute { get; set; }
    public MyStation(Station a)
    {
        this.IDStation = a.IDStation;
        this.nextStation = new List<nextStaion>();
        this.IDBusRoute = new List<int>();
    }
}
public class Vertex
    {
        public int id = -1;
        public int flag = -1;
        public List<int> next;
        public List<double> nextValue;
        public double hh = 0;
        public double g = 0;
        public int before = -1;
        public Vertex()
        {
            next = new List<int>();
            nextValue = new List<double>();
            hh = 0;
        }
    }